/*
 * $Id: fsm_mkdir.c,v 1.8 2005-11-05 16:52:26 bacon Exp $
 */

#include <xp/utl/fsm.h>
#include <xp/bas/errno.h>

int xp_fsm_mkdir (
	xp_fsm_t* fsm, const xp_char_t* path, xp_mode_t mode, int flags)
{
	xp_char_t buf[XP_PATH_MAX + 1];
	xp_char_t * p;

	if (xp_trimpath(path, buf, xp_countof(buf)) == (xp_size_t)-1) {
		fsm->errnum = (xp_errno == XP_ENOMEM)? 
			XP_FSM_ENOMEM: XP_FSM_EINVAL;
		return -1;
	}

	p = buf;
	if (*p == XP_CHAR('\0')) {
		/* path can't be empty */
		fsm->errnum = XP_FSM_EINVAL;
		return -1;
	}

#ifdef _WIN32
	while (*p != XP_CHAR('\0')) {
		if (*p == XP_CHAR('/')) *p = XP_CHAR('\\');
		p++;
	}
	p = buf;

	if (flags & XP_FSM_MKDIR_PARENTS) {
		if (*p == XP_CHAR('\\') && p[1] == XP_CHAR('\\')) p += 2;
	}
#endif

	while (1) {
		xp_char_t c = XP_CHAR('\0');

		if (flags & XP_FSM_MKDIR_PARENTS) {
			while (*p != XP_CHAR('\0')) {
#ifdef _WIN32
				if (p > buf && *p == XP_CHAR('\\')) {
#else
				if (p > buf && *p == XP_CHAR('/')) {
#endif
					c = *p;
					*p = XP_CHAR('\0');
					break;
				}
				p++;
			}
		}

		if (xp_mkdir(buf, mode) == -1) {
			if (xp_errno == XP_EEXIST)  {
				if (c == XP_CHAR('\0')) {
					/* the last directory */
					fsm->errnum = XP_FSM_EEXIST;
					return -1;
				}

				/* don't really care if the existing path
				 * is a file or a directory. just continue */
			}
			else {
				fsm->errnum = (xp_errno == XP_EACCES)? 
					XP_FSM_EACCES: XP_FSM_EMKDIR;
				return -1;
			}
		}

		if (c == XP_CHAR('\0')) {
			/* the last directory */
			break;
		}

		*p++ = c;
	} 

	return 0;
}
